package com.hogocloud.corelibrary.base

import android.annotation.SuppressLint
import com.hogocloud.corelibrary.http.*
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Function
import io.reactivex.observers.DisposableObserver
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory

/**
 * Created by goldze on 2017/6/15.
 */
open class BaseRepository(private val baseViewModelEvent: IView?) {

    private lateinit var mRetrofit: Retrofit
    //管理RxJava，主要针对RxJava异步操作造成的内存泄漏
    private var mCompositeDisposable: CompositeDisposable? = null

    init {
        initRetrofit()
    }

    protected fun initRetrofit(baseUrl: String = HttpConstants.BASE_URL) {
        mRetrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(HttpClientHelper.instance.okHttpClient)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    protected fun <T> create(t: Class<T>): T {
        return mRetrofit.create(t)
    }

    protected fun <T> execute(observable: Observable<BaseResponse<T>>, callback: RequestCallback<T>?, quietly: Boolean = false) {
        execute(observable, CommonSubscriber(callback), quietly)
    }

    @SuppressLint("CheckResult")
    private fun <T> execute(observable: Observable<BaseResponse<T>>, observer: DisposableObserver<OptionT<T>>, quietly: Boolean) {
        observable.compose(RxHelper.rxOtSchedulerHelper())
            .doOnSubscribe {
                if (!quietly) {
                    showLoading()
                }
            }
            .doFinally {
                if (!quietly) {
                    dismissLoading()
                }
            }
            .flatMap(object : Function<BaseResponse<T>, ObservableSource<OptionT<T>>> {
                override fun apply(t: BaseResponse<T>): ObservableSource<OptionT<T>> {
                    when {
                        t.code == 200 || t.success -> {
                            val optional: OptionT<T> = OptionT(t.data)
                            return createData(optional)
                        }
                        else -> {
                            throw ServerResultException(t.msg ?: "未知错误", t.code)
                        }
                    }
                }
            })
            .subscribeWith(observer)
    }

    private fun <T> createData(t: T): Observable<T> {
        return Observable.create { emitter ->
            try {
                emitter.onNext(t)
                emitter.onComplete()
            } catch (e: Exception) {
                emitter.onError(e)
            }
        }
    }

    private fun showLoading() {
        baseViewModelEvent?.showLoading("")
    }

    private fun dismissLoading() {
        baseViewModelEvent?.hideLoading()
    }
}
